#include "battery.h"
#include <avr/io.h>
#include <avr/interrupt.h>

#define BATT_PORT PORTD
#define BATT_DDR DDRD
/**
 * @brief Pin where the battery voltage will be readed.
 */
#define BATT_PIN PD7

//ADC value when ADC0 reaches 2,6 V (battery power = 5,2 V)
#define ADC_BATT_100 150

#if NXBOT_USE_12VBATT==1
//Value of ADC when battState should report 0%
#define ADC_BATT_0 64 
//Value of ADC when Batt. Led should be RED (No battery).
#define ADC_BATT_LIMIT 69
//Values of ADC higher than this should report 100% in battState
#define BATT_VOLT_MAX 1200
#define BATT_VOLT_MIN 1000
#else
//Value of ADC when battState should report 0%
#define ADC_BATT_0 134
//Value of ADC when Batt. Led should be RED (No battery).
#define ADC_BATT_LIMIT 142
#define BATT_VOLT_MAX 600
#define BATT_VOLT_MIN 500
#endif

#define BATT_LINEALIZE 4



//variable that reports amount of power, from 0% to 100%
static unsigned char battState;
//variable that reports amount of power, in volts. From 0 to 600 (assuming 6V battery) or 0 to 1200 (assuming 12V battery)
static unsigned int battVoltage;

static unsigned char adc_chan1;


void battery_init()
{
	BATT_DDR |= (1<<BATT_PIN);
	
	//Configuration of ADC
	//Resolution of 8 bits (ADLAR, left Adjust), AVCC reference.	
	ADMUX |= (1<<REFS0) | (1<<ADLAR);
	//Enable ADC, Start conversion, Auto trigger enable, Interrupt enable.
	ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
	//Disable digital input from all ADC channels. This will reduce consumption power.
	DIDR0 = 0xFF; //|= (1<<ADC0D);
}

void adc_changeChannel(unsigned char channel)
{
	channel &= 0x07;
	ADMUX |= (1<<REFS0) | (1<<ADLAR) | channel;
}

unsigned char adc_getChannel()
{
	unsigned char channel;
	
	channel = ADMUX & 0x07;
	
	return channel;
}

//TODO: Solo esta retornando el canal 1. Falta configurar para los demas canales
unsigned char adc_read(unsigned char channel)
{
	return adc_chan1;
}


void battery_ledEnable(unsigned char en)
{
	if(en)
		BATT_PORT |= (1<<BATT_PIN);
	else
		BATT_PORT &= ~(1<<BATT_PIN);
}

unsigned char battery_getState()
{
	return battState;
}


unsigned int battery_getVoltage()
{
	return battVoltage;
}

unsigned int battery_read(unsigned char type)
{
	if(type == BATT_READ_VOLT)
		return battVoltage;
	else
		return battState;
		
}

//TODO: Lo mejor es pasar todo el codigo de transformacion a la lectura de bateria al codigo de sensors.c. Esta libreria debe dejarse
// exclusivamente para lecturas del ADC. Ademas, lo mejor sera que en la interrupcion se cambie al siguiente canal analogico, de tal
//manera que se logre una actualizacion a la frecuencia que muestrea el ADC.
ISR(ADC_vect)
{
	unsigned char channel;
	channel = ADMUX & 0x07;
	
	//we are reading the battery voltage
	if(!channel)
	{
		//battery voltage = ADCH * 4. BATT_LINEALIZE
		#if NXBOT_USE_12VBATT==1
		battVoltage = ((ADCH - BATT_LINEALIZE)<<3);	
		#else
		battVoltage = ((ADCH - BATT_LINEALIZE)<<2);	
		#endif	
	
		//when battery is full
		if(ADCH>ADC_BATT_100)
			battState = 100;
		//when battery is empty
		else if(ADCH<ADC_BATT_0)
			battState = 0;
		else
			#if NXBOT_USE_12VBATT==1
			battState = (char)((battVoltage>>2)-BATT_VOLT_MIN);			
			#else
			battState = (char)(battVoltage-BATT_VOLT_MIN);	
			#endif

		//inform battery state to user
		if(ADCH<=ADC_BATT_LIMIT)
			battery_ledEnable(OFF);
		else
			battery_ledEnable(ON);
	}
	//we are reading other adc channels
	//TODO: Aqui es donde debe aplicarse el cambio para guardar en un array de ints las lecturas del ADC.
	else
	{
		adc_chan1 = ADCH;
	}
	
}
